package base

import (
	"fmt"
	"jgt-sdk/oper"
	"net/http"
	"strconv"
	"strings"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/ginsrv/valid"
	validator "gopkg.in/go-playground/validator.v9"

	"github.com/gin-gonic/gin"
	"github.com/go-session/session"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/ginsrv/api/ginsess"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/ginsrv/oplog"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/oplogd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd/ginhook"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

// BaseContrl 基础控制器
type BaseContrl struct {
	Domain core.CmsDomain
}

// DDDContext 获取领域上下文
func (c BaseContrl) DDDContext(ctx *gin.Context) ddd.Context {
	return ginhook.FromContext(ctx)
}

// OperHandler 获取 oper.Handle
func (c BaseContrl) OperHandler(ctx *gin.Context) *oper.Handle {
	traceid := ctx.GetHeader("X-Request-Id")
	return oper.GetHandleWithTraceID(traceid)
}

// Logger 日志
func (c BaseContrl) Logger(ctx *gin.Context) log.ILogger {
	return log.FromContext(ctx)
}

// ErrUnauthorized 返回401认证失败
func (c BaseContrl) ErrUnauthorized(ctx *gin.Context, msg string, err ...error) {
	opResult(ctx, http.StatusUnauthorized, 1, msg, nil, err...)
}

// ErrServerError 返回500错误
func (c BaseContrl) ErrServerError(ctx *gin.Context, code int, msg string, err ...error) {
	opResult(ctx, http.StatusInternalServerError, code, msg, nil, err...)
}

// ErrBadRequest 返回400错误
func (c BaseContrl) ErrBadRequest(ctx *gin.Context, code int, msg string, err ...error) {
	opResult(ctx, http.StatusBadRequest, code, msg, nil, err...)
}

// ErrForbidden 返回403错误
func (c BaseContrl) ErrForbidden(ctx *gin.Context, msg string, err ...error) {
	opResult(ctx, http.StatusForbidden, 1, msg, nil, err...)
}

// ErrBadRequestByBind 返回400错误
func (c BaseContrl) ErrBadRequestByBind(ctx *gin.Context, code int, err error) {
	msg := err.Error()
	if e, ok := err.(validator.ValidationErrors); ok {
		if t := valid.FromContext(ctx); t != nil {
			v := e.Translate(t)
			msg = ""
			for _, v := range v {
				msg = v
				break
			}
			//msg = fmt.Sprintf("请求参数错误:%v", e.Translate(t))
		}
	}
	opResult(ctx, http.StatusBadRequest, code, msg, nil, err)
}

// ErrNotFound 返回404认证失败
func (c BaseContrl) ErrNotFound(ctx *gin.Context, code int, msg string, err ...error) {
	opResult(ctx, http.StatusNotFound, code, msg, nil, err...)
}

// Success 返回200成功
func (c BaseContrl) Success(ctx *gin.Context, data interface{}) {
	if data == nil {
		data = "ok"
	}
	opResult(ctx, http.StatusOK, Success, "", data, nil)
}

// SuccessPage 返回200成功
func (c BaseContrl) SuccessPage(ctx *gin.Context, pi common.PageInfo, pr common.PageResult, data interface{}) {
	if data == nil {
		// 分页返回空数组
		data = make([]string, 0)
	}
	if pi.Mode == common.PageModeID {
		// id 分页

		c.Success(ctx, data)
		return
	}
	// 指定页码分页
	c.Success(ctx, map[string]interface{}{
		"pagination": pr,
		"list":       data,
	})
	return
}

// // 返回200 失败，请求参数错误
// func (c BaseContrl) FailureBadRequest(ctx *gin.Context, msg string, err ...error) {
// 	opResult(ctx, http.StatusOK, FailedBadRequest, msg, nil, err...)
// }

// // Failure 返回200 失败，自定义失败
// func (c BaseContrl) Failure(ctx *gin.Context, code int, msg string, err ...error) {
// 	opResult(ctx, http.StatusOK, code, msg, nil, err...)
// }

// Session 获取会话
func (c BaseContrl) Session(ctx *gin.Context) session.Store {
	return ginsess.FromContext(ctx)
}

// GetUID 获取当前用户
func (c BaseContrl) GetUID(ctx *gin.Context) string {
	if v, ok := ctx.Get("__uid__"); ok && v != nil {
		return v.(string)
	}
	return ""
}

// GetOrgID 获取当前用户所在组织
func (c BaseContrl) GetOrgID(ctx *gin.Context) string {
	if v, ok := ctx.Get("__orgid__"); ok && v != nil {
		return v.(string)
	}
	return ""
}

// GetIntByQuery 获取query中的整数值
func (c BaseContrl) GetIntByQuery(ctx *gin.Context, key string, defaultValue int) int {
	v := ctx.Query(key)
	if v == "" {
		return defaultValue
	}
	if i, err := strconv.Atoi(v); err == nil {
		return i
	}
	return defaultValue
}

// GetIntArrayByQuery 获取query中的整数数组值
func (c BaseContrl) GetIntArrayByQuery(ctx *gin.Context, key string, defaultValue []int) (result []int) {
	vs := ctx.QueryArray(key)
	if vs == nil {
		return defaultValue
	}
	for _, v := range vs {
		if i, err := strconv.Atoi(v); err == nil {
			result = append(result, i)
		}
	}

	return
}

// GetSchTimeByQuery 获取query中的时间查询
func (c BaseContrl) GetSchTimeByQuery(ctx *gin.Context, key string) (t *common.SchTime) {
	value := ctx.Query(key)
	if value == "" {
		return nil
	}
	t = common.ParseSchTime(value)
	return
}

// GetBoolByQuery 获取query中的整数值
func (c BaseContrl) GetBoolByQuery(ctx *gin.Context, key string, defaultValue bool) bool {
	v := ctx.Query(key)
	if v == "" {
		return defaultValue
	}
	if v == "0" || v == "false" {
		return false
	}
	return true
}

// GetPageInfo 获取query中的整数值
// defaultMode 默认分页模式
func (c BaseContrl) GetPageInfo(ctx *gin.Context, defaultMode int) (pi common.PageInfo) {
	pi.Desc = c.GetBoolByQuery(ctx, "desc", true)
	pi.Mode = c.GetIntByQuery(ctx, "mode", defaultMode)
	pi.PageSize = c.GetIntByQuery(ctx, "pageSize", 10)
	pi.Direct = c.GetIntByQuery(ctx, "direct", 0)
	pi.Current = c.GetIntByQuery(ctx, "current", 1)
	pi.PageID = ctx.DefaultQuery("lastID", "")
	if pi.PageSize > 100 {
		pi.PageSize = 100
	}
	return
}

// ParamArray 解析path路径中的数组参数
// 使用,分割的变量切分为字符串数组
func (c BaseContrl) ParamArray(ctx *gin.Context, key string) []string {

	tmp := ctx.Param(key)
	if tmp == "" {
		return nil
	}
	return strings.Split(tmp, ",")
}

// ParamInt 获取整数
func (c BaseContrl) ParamInt(ctx *gin.Context, key string, def int) int {

	tmp := ctx.Param(key)
	if tmp == "" {
		return def
	}
	if i, err := strconv.Atoi(tmp); err != nil {
		return def
	} else {
		return i
	}
}
func opResult(ctx *gin.Context, httpstatus int, status int, errstr string, output interface{}, err ...error) {
	var out interface{}
	switch httpstatus {
	case http.StatusOK:
		// 成功
		out = output
	default:
		tmp := gin.H{"code": status}
		if errstr != "" {
			tmp["message"] = errstr
		}
		out = tmp
	}
	ctx.JSON(httpstatus, out)
	oplog.WrapModules(ctx, func(ol *oplogd.OpLogEntity) {
		ol.HTTPStatus = httpstatus
		ol.Output = out
		if len(err) > 0 {
			if err[0] != nil {
				ol.Err = fmt.Sprintf("%+v", err[0])
				log.FromContext(ctx).Warnf("%v %+v", ol.Input, ol.Err)
			}
		}
	})
}
